package org.wattdepot.gdata.kukuicup.service;

import org.wattdepot.client.WattDepotClient;
import org.wattdepot.gdata.kukuicup.GDataProperties;

/**
 * Provides read-only, anonymous access to the WattDepot service.
 * The URI of the server must be available in the passed properties file.  
 * @author Philip Johnson
 */
public class WattDepotService {
  
  /** WattDepot server URL. */
  private String wattDepotUrl;
  /** The WattDepot client (cached after initial creation). */
  private WattDepotClient wattDepotClient = null;
  
  /** The GData properties instance. */
  private GDataProperties properties;

  /**
   * Initialize this instance from the properties file.
   * Throws a RuntimeException if the properties are 
   * not available or the file is not found or if the client cannot be connected to.
   * @param properties The GDataProperties instance.
   */
  public WattDepotService(GDataProperties properties) {
    this.wattDepotUrl = properties.getWattDepotUri();
    this.properties = properties;
    // Check that we can contact the WattDepot client and that it is healthy. 
    if (!getClient().isHealthy()) {
      System.out.format("WattDepot server at %s is not available.", wattDepotUrl);
      retryClient(getClient());  //NOPMD (allow call to overridable methods.)
    }
  }
  
  /**
   * Returns an anonymous, read-only WattDepot client.
   * Throws a runtime exception if the WattDepot server could not be connected to.
   * @return The WattDepot client instance. 
   */
  public WattDepotClient getClient() {
    // If we've cached it, return it immediately.
    if (this.wattDepotClient != null) {
      return this.wattDepotClient;
    }
    // Otherwise create and cache the WattDepotClient.
    WattDepotClient client = new WattDepotClient(wattDepotUrl);
    if (!client.isHealthy()) {
      System.out.format("Could not connect to: %s%n", wattDepotUrl); 
      retryClient(client);
    }
    this.wattDepotClient = client;
    return client;
  }
  
  /**
   * Returns the GDataProperties instance for this run of the system.
   * Used to access Updater-specific properties. 
   * @return The GDataProperties instance.
   */
  public GDataProperties getProperties() {
    return this.properties;
  }
  
  /**
   * Failure to connect to a client might be simply due to startup process sequencing. 
   * Thus, this method pauses twice for two minutes and attempts to see if the connection 
   * succeeds.  If it does not after two minutes, it throws a RuntimeException.
   * @param client The WattDepot client. 
   * @throws InterruptedException 
   */
  private void retryClient(WattDepotClient client) {
    String msg = "WARNING: Pausing for 60 seconds, then retrying connection to client %s%n";
    String clientUrl = client.getWattDepotUri();
    try {
      System.out.format(msg, clientUrl);
      Thread.sleep(60000);
      if (client.isHealthy()) {
        return;
      }
      else {
        System.out.format(msg, client.getWattDepotUri());
        Thread.sleep(60000);
        if (!client.isHealthy()) {
          System.out.format("ERROR: Could not connect to client %s. Exiting.", clientUrl);
          throw new RuntimeException("Could not connect to client: " + clientUrl);
        }
      }
      System.out.println("ERROR: Exception during WattDepot client retry. Exiting.");
      throw new RuntimeException("Could not connect to client: " + clientUrl);
    }
    catch (InterruptedException e) {
      throw new RuntimeException("Caught interrupted exception", e);
    }
  }
 
} 
